///////////////////////////////////////////////////////////////////////////////
//
/// Copyright (c) 2022- ThunderSoft
/// All Rights Reserved by Thunder Software Technology Co., Ltd and its affiliates.
/// You may not use, copy, distribute, modify, transmit in any form this file
/// except in compliance with ThunderSoft in writing by applicable law.
//
///////////////////////////////////////////////////////////////////////////////

#ifndef _DRA_COM_SOMEIP_DESERIALIZER_H_
#define _DRA_COM_SOMEIP_DESERIALIZER_H_

#include <mutex>
// #include "dra/core/typedefine.h"
#include "serialize/typedefine.h"
#include "serialize/IDeserializer.h"
// #include "dra/core/defines.h"
#include "serialize/defines.h"
#include "serialize/serializeCommon.h"
// #include "logwrapper/logwrapper.h"
#ifndef GOS_LOG_TAG
#define GOS_LOG_TAG "DCOM"  // NOLINT
#endif

#define GOS_LOG_ERR(...) \
    if (false) {fprintf(stderr, __VA_ARGS__), fprintf(stderr, "\n");}
#define GOS_LOG_INFO(...) \
    if (false) {fprintf(stdout, __VA_ARGS__), fprintf(stdout, "\n");}

namespace dra {
namespace com {
// namespace someip {

// using namespace deviceware::base;

class DRA_EXPORT Deserializer : public IDeserializer {
public:
    virtual BOOLEAN getInt32(INT32 & i){return read(i);}
    virtual BOOLEAN getString(CHAR const* &str, INT32 & retStrLen){
        if (m_icurAddrPos + retStrLen <= m_desrialObjLen &&
            transProps.stringEncoding == BaseTypeEncodingString::UTF_8) {
            str = (CHAR*)(m_pdataStartAddr + m_icurAddrPos);
            m_icurAddrPos += retStrLen;
            return true;
        }
        return false;
    }
    // Begin Only For ETS Test-------------------------------------------------------
    virtual BOOLEAN getString([[maybe_unused]] CHAR const*& str, [[maybe_unused]] INT32& retStrLen, 
        [[maybe_unused]] UINT32 lf_len, [[maybe_unused]] BaseTypeEncodingString encodeType){return false;}
    // End   Only For ETS Test-------------------------------------------------------
    virtual BOOLEAN getBoolean(BOOLEAN & b){return read(b);}
    virtual BOOLEAN getInt8(INT8 & i){return read(i);}
    virtual BOOLEAN getInt16(INT16 & i){return read(i);}
    virtual BOOLEAN getInt64(INT64 & i){return read(i);}
    virtual BOOLEAN getUInt8(UINT8 & i){return read(i);}
    virtual BOOLEAN getUInt16(UINT16 & i){return read(i);}
    virtual BOOLEAN getUInt32(UINT32 & i){return read(i);}
    virtual BOOLEAN getUInt64(UINT64 & i){return read(i);}
    virtual BOOLEAN getFloat32(FLOAT32 & f){return read(f);}
    virtual BOOLEAN getFloat64(FLOAT64 & f){return read(f);}
    virtual BOOLEAN getFD([[maybe_unused]] INT32 & fd){return false;}
    virtual SERIALIZE_TYPE GetSerializeType() {
        return SERIALIZE_TYPE::SOMEIP;
    }

    VOID setDeserialDataAddr(UINT8* dataAddr, INT32 len){
        m_pdataStartAddr = dataAddr;
        m_icurAddrPos = 0;
        m_desrialObjLen = len;
    }
#ifdef HAS_E2EXF
    VOID setDeserializeDataAddrE2E(UINT32 &dataid, CHAR* dataAddr, INT32 len);
    VOID getE2EState(int & e2eState, int & e2eCheckStatus);
#endif  // HAS_E2EXF
    BOOLEAN getSerialDataLen([[maybe_unused]] INT32& sdataLen){ return m_desrialObjLen;}
    UINT32 getRemainedDataLen() {
        return m_desrialObjLen - m_icurAddrPos;
    }

    Deserializer(): m_pdataStartAddr(nullptr),
        m_icurAddrPos(0),
        m_desrialObjLen(0){;}
    virtual ~Deserializer(){;}

private:
    template<typename T>
    BOOLEAN getBasicType(T & t, INT32 iType);

    template < typename ArgumentType_ >
    bool read(ArgumentType_& value) {
        // GOS_LOG_INFO("read in curPos:%d, len:%d, req size:%lu\n", 
        //     m_icurAddrPos, m_desrialObjLen, sizeof(ArgumentType_));
        if (m_icurAddrPos + sizeof(ArgumentType_) <= m_desrialObjLen
            && m_pdataStartAddr) {
            memcpy(&value, m_pdataStartAddr+m_icurAddrPos, sizeof(ArgumentType_));
            m_icurAddrPos += sizeof(ArgumentType_);
            return true;
        }
        GOS_LOG_ERR("curPos:%d, len:%d, req size:%lu\n", 
            m_icurAddrPos, m_desrialObjLen, sizeof(ArgumentType_));
        return false;
    }

    // for string
    BOOLEAN checkBOM(UINT8* bom, INT32 strBytesLen);
    BOOLEAN convert2UTF8(CHAR* inbuf, size_t inbytesleft, CHAR* outbuf, size_t& outbytesleft);
    INT32 getBytesByTermination(CHAR* pChar);
    // Begin Only For ETS Test------------------------------------------------------
    BOOLEAN checkBOM(UINT8* bom, INT32 strBytesLen, BaseTypeEncodingString encodeType);
    BOOLEAN convert2UTF8(CHAR* inbuf, size_t inbytesleft, CHAR* outbuf, size_t& outbytesleft,
                BaseTypeEncodingString encodeType);
    INT32 getBytesByTermination(CHAR* pChar, BaseTypeEncodingString encodeType);
    // End   Only For ETS Test-------------------------------------------------------

private:
    UINT8* m_pdataStartAddr;
    INT32 m_icurAddrPos;
    INT32 m_desrialObjLen;
    std::mutex m_mtx_syn;
};


// length field serialization -----------------------------------------------------------------------------------------
// Begin Only For ETS Test---------------------------------------------------------------------------------------------
inline UINT32 GetDeserializerLengthFieldLength(UINT32 len) {
    UINT32 lf_len = len;
    if ((len != 1) && (len != 2) && (len != 4)) {
        lf_len = 0;
    }
    return lf_len;
}
// End   Only For ETS Test---------------------------------------------------------------------------------------------

BOOLEAN deserialize_lf(IDeserializer *d, UINT32 sizeOfLengthField, UINT32& length);
// c array serialization ----------------------------------------------------------------------------------------------
template <typename T>
BOOLEAN deserialize_carray(IDeserializer *d, T* a, size_t size);

template <typename T, typename Enalbe = void>
struct deserialize_wrapper {
    static BOOLEAN get(IDeserializer* d, T& t,
        std::enable_if_t<std::is_same<BOOLEAN, decltype(t.deserialize(d))>::value>* = nullptr) {
        GOS_LOG_ERR("deserialize_wrapper get:%d\n", __LINE__);
        return t.deserialize(d);
    }
};

template <typename T>
struct deserialize_wrapper <T, typename std::enable_if_t<std::is_enum<T>::value>> {
    static BOOLEAN get(IDeserializer* d, T& t) {
        GOS_LOG_INFO("deserialize_wrapper get:%d\n", __LINE__);
        std::underlying_type_t<T> tmp;
        BOOLEAN ret = deserialize_wrapper<std::underlying_type_t<T>>::get(d, tmp);  // bug005, get 直接传t会报错
        t = static_cast<T>(tmp);
        return ret;
    }
};

template <typename T>
struct deserialize_wrapper <T, typename std::enable_if_t<IsStruct<T>::value>> {
    static BOOLEAN get(IDeserializer* d, T& t) {
        GOS_LOG_INFO("deserialize_wrapper get:%d\n", __LINE__);
        UINT32 length = 0;
        BOOLEAN ret = deserialize_lf(d, transProps.sizeOfStructLengthField, length);
        if (ret) {
            if (length <= reinterpret_cast<Deserializer*>(d)->getRemainedDataLen()) {
                ret = t.deserialize(d);
            } else {
                ret = false;
            }
        }
        return ret;
    }
};

template <typename T>
struct deserialize_wrapper <T, typename std::enable_if_t<IsUnion<T>::value>> {
    static BOOLEAN get(IDeserializer* d, T& t) {
        GOS_LOG_INFO("deserialize_wrapper get:%d\n", __LINE__);
        UINT32 length = 0;
        BOOLEAN ret = deserialize_lf(d, transProps.sizeOfUnionLengthField, length);
        if (ret) {
            if (length <= (dynamic_cast<Deserializer*>(d)->getRemainedDataLen() - 4)) {
                ret = t.deserialize(d);
                if (length < t.GetLength(SERIALIZE_TYPE::SOMEIP)) {
                    ret = false;
                }
            } else {
                ret = false;
            }
        }
        return ret;
    }
};

template <typename T>
struct deserialize_wrapper<T*> {
    static BOOLEAN get(IDeserializer* d, T*& t,
        std::enable_if_t<std::is_same<BOOLEAN, decltype(t->deserialize(d))>::value>* = nullptr) {
        GOS_LOG_INFO("deserialize_wrapper get:%d\n", __LINE__);
        return t->deserialize(d);
    }
};

template <>
struct deserialize_wrapper<BOOLEAN> {
    static BOOLEAN get(IDeserializer *d, BOOLEAN &b) {
        GOS_LOG_INFO("deserialize_wrapper get:%d\n", __LINE__);
        return d->getBoolean(b);
    }
};

template <>
struct deserialize_wrapper<FLOAT32> {
    static BOOLEAN get(IDeserializer *d, FLOAT32 &f) {
        GOS_LOG_INFO("deserialize_wrapper get:%d\n", __LINE__);
        return d->getFloat32(f);
    }
};

template <>
struct deserialize_wrapper<FLOAT64> {
    static BOOLEAN get(IDeserializer *d, FLOAT64 &f) {
        GOS_LOG_INFO("deserialize_wrapper get:%d\n", __LINE__);
        return d->getFloat64(f);
    }
};

template <>
struct deserialize_wrapper<INT32> {
    static BOOLEAN get(IDeserializer *d, INT32 &i) {
        GOS_LOG_INFO("deserialize_wrapper get:%d\n", __LINE__);
        return d->getInt32(i);
    }
};

template <>
struct deserialize_wrapper<INT8> {
    static BOOLEAN get(IDeserializer *d, INT8 &i) {
        GOS_LOG_INFO("deserialize_wrapper get:%d\n", __LINE__);
        return d->getInt8(i);
    }
};

template <>
struct deserialize_wrapper<char> {
    static BOOLEAN get(IDeserializer *d, char &i) {
        GOS_LOG_INFO("deserialize_wrapper get:%d\n", __LINE__);
        INT8 ii = 0;
        BOOLEAN ret = d->getInt8(ii);
        i = static_cast<char>(ii);
        return ret;
    }
};

template <>
struct deserialize_wrapper<INT16> {
    static BOOLEAN get(IDeserializer *d, INT16 &i) {
        GOS_LOG_INFO("deserialize_wrapper get:%d\n", __LINE__);
        return d->getInt16(i);
    }
};

template <>
struct deserialize_wrapper<INT64> {
    static BOOLEAN get(IDeserializer *d, INT64 &i) {
        GOS_LOG_INFO("deserialize_wrapper get:%d\n", __LINE__);
        return d->getInt64(i);
    }
};

#if !defined(__aarch64_oe__) && !defined(__aarch32_oe__) && !defined(__ANDROID__)
template <>
struct deserialize_wrapper<int64_t> {
    static BOOLEAN get(IDeserializer *d, int64_t &i) {
        GOS_LOG_INFO("deserialize_wrapper get:%d\n", __LINE__);
        INT64 ii;
        BOOLEAN ret = d->getInt64(ii);
        i = static_cast<int64_t>(ii);
        return ret;
    }
};
#endif

template <>
struct deserialize_wrapper<UINT32> {
    static BOOLEAN get(IDeserializer *d, UINT32 &i) {
        GOS_LOG_INFO("deserialize_wrapper get:%d\n", __LINE__);
        return d->getUInt32(i);
    }
};

template <>
struct deserialize_wrapper<wchar_t> {
    static BOOLEAN get(IDeserializer *d, wchar_t &i) {
        GOS_LOG_INFO("deserialize_wrapper get:%d\n", __LINE__);
        UINT32 ii;
        BOOLEAN ret = d->getUInt32(ii);
        i = static_cast<wchar_t>(ii);
        return ret;
    }
};

template <>
struct deserialize_wrapper<UINT8> {
    static BOOLEAN get(IDeserializer *d, UINT8 &i) {
        GOS_LOG_INFO("deserialize_wrapper get:%d\n", __LINE__);
        return d->getUInt8(i);
    }
};

template <>
struct deserialize_wrapper<UINT16> {
    static BOOLEAN get(IDeserializer *d, UINT16 &i) {
        GOS_LOG_INFO("deserialize_wrapper get:%d\n", __LINE__);
        return d->getUInt16(i);
    }
};

template <>
struct deserialize_wrapper<UINT64> {
    static BOOLEAN get(IDeserializer *d, UINT64 &i) {
        GOS_LOG_INFO("deserialize_wrapper get:%d\n", __LINE__);
        return d->getUInt64(i);
    }
};

#if !defined(__aarch64_oe__) && !defined(__aarch32_oe__) && !defined(__ANDROID__)
template <>
struct deserialize_wrapper<uint64_t> {
    static BOOLEAN get(IDeserializer *d, uint64_t &i) {
        GOS_LOG_INFO("deserialize_wrapper get:%d\n", __LINE__);
        UINT64 ii;
        BOOLEAN ret = d->getUInt64(ii);
        i = static_cast<uint64_t>(ii);
        return ret;
    }
};
#endif

template <>
struct deserialize_wrapper<STRING> {
    static BOOLEAN get(IDeserializer* d, STRING& str) {
        GOS_LOG_INFO("deserialize_wrapper get:%d\n", __LINE__);
        INT32 getStrLen = str.length();   // bug011
        BOOLEAN ret = false;

        CHAR const* strPtr = nullptr;

        ret = d->getString(strPtr, getStrLen);
        if (true == ret && nullptr != strPtr) {
            str.assign(strPtr, getStrLen);
            if (transProps.stringEncoding != BaseTypeEncodingString::UTF_8 && nullptr != strPtr) {
                delete[] strPtr;
            }
        }

        return ret;
    }
};

// Begin Only For ETS Test---------------------------------------------------------------------------------------------
template <UINT32 L, BaseTypeEncodingString E>
struct deserialize_wrapper<STRINGW<L, E>> {
    static BOOLEAN get(IDeserializer* d, STRINGW<L, E>& str) {
        GOS_LOG_INFO("deserialize_wrapper get:%d\n", __LINE__);
        INT32 getStrLen = str.str.length();   // bug011
        BOOLEAN ret = false;

        CHAR const* strPtr = nullptr;
        UINT32 lf_len = GetDeserializerLengthFieldLength(L);
        ret = static_cast<Deserializer*>(d)->getString(strPtr, getStrLen, lf_len, E);
        if (true == ret && nullptr != strPtr) {
            str.str.assign(strPtr, getStrLen);
            if (E != BaseTypeEncodingString::UTF_8 && nullptr != strPtr) {
                delete[] strPtr;
            }
        }
        return ret;
    }
};
// End   Only For ETS Test---------------------------------------------------------------------------------------------

template <>
struct deserialize_wrapper<fd_t> {
    static BOOLEAN get(IDeserializer* d, fd_t& fd) {
        GOS_LOG_INFO("deserialize_wrapper get:%d\n", __LINE__);
        return d->getFD(fd.value);
    }
};

/** \uptrace{SWS_CM_10428} */
#if 0
template <>
struct deserialize_wrapper<ara::core::ErrorCode> {
    static BOOLEAN get(IDeserializer* d, ara::core::ErrorCode& err) {
        // return d->getFD(fd.value);
        using union_length_type = UINT32;
        using union_type_type = UINT8;
        using struct_length_type = UINT16;
        using domain_value_type = UINT64;
        using error_code_type = UINT32;
        using support_data_type = UINT32;

        union_length_type union_len;
        union_type_type union_type;
        struct_length_type struct_len;
        domain_value_type domain_value;
        error_code_type error_code;
        support_data_type support_data;

        if ( d->getUInt32(union_len) &&
                d->getUInt8(union_type) &&
                d->getUInt16(struct_len) &&
                d->getUInt64(domain_value) &&
                d->getUInt32(error_code) &&
                d->getUInt32(support_data)) {
            err.SetValue(error_code);
            err.SetSupportData(support_data);
            const ara::core::ErrorDomain& domain = \
                            ara::core::error_domains::Registry::getDomain(domain_value);
            err.SetDomain(const_cast<ara::core::ErrorDomain*>(&domain));
            return true;
        }

        return false;
    }
};
#endif

template <typename F, typename... R>
struct deserialize_traveller {
    inline static BOOLEAN deserialize(IDeserializer* d, F& f, R&... r) {
        GOS_LOG_INFO("deserialize_traveller deserialize:%d\n", __LINE__);
        return (deserialize_traveller<F>::deserialize(d, f) \
                && deserialize_traveller<R...>::deserialize(d, r...));
    }
};

template <typename F>
struct deserialize_traveller<F> {
    inline static BOOLEAN deserialize(IDeserializer *d, F &f) {
        GOS_LOG_INFO("deserialize_traveller deserialize:%d\n", __LINE__);
        return deserialize_wrapper<F>::get(d, f);
    }
};

// std::tuple
template <typename... Args>
struct deserialize_traveller<std::tuple<Args...>> {
    inline static BOOLEAN deserialize(IDeserializer* d, std::tuple<Args...>& t) {
        GOS_LOG_INFO("std::tuple in\n");
        using indices_for = std::make_index_sequence<std::tuple_size<std::tuple<Args...>>::value>;
        return _deserialize(d, t, indices_for{});
    }

private:
    template <std::size_t... Is>
    inline static BOOLEAN _deserialize(IDeserializer* d, std::tuple<Args...>& t, \
                const std::index_sequence<Is...>&) {
        BOOLEAN ret = false;
        INT32 tupleSize_src = 0;
        GOS_LOG_INFO("deserialize type: std::tuple, get tuple data by basic type.\n");
        ret = deserialize_traveller<INT32>::deserialize(d, tupleSize_src);
        INT32 tupleSize_dest = std::tuple_size<std::tuple<Args...>>::value;
        if ((true == ret) && (tupleSize_src > 0) && (tupleSize_dest == tupleSize_src)) {
            return deserialize_traveller<Args...>::deserialize(d, std::get<Is>(t)...);
        }
        GOS_LOG_ERR("deserialize type: std::tuple, fail by dest deserial tuple size is not enough\n");
        return false;
    }
};

// std::array
template <typename T, std::size_t N>
struct deserialize_traveller<std::array<T, N>> {
    inline static BOOLEAN deserialize(IDeserializer* d, std::array<T, N>& a) {
        GOS_LOG_INFO("deserialize_traveller deserialize:%d\n", __LINE__);
        BOOLEAN ret = false;
        UINT32 bytes = a.size()*sizeof(T);
        // GOS_LOG_INFO("deserialize type: std::array, get array data by basic type.\n");
        ret = deserialize_lf(d, 0, bytes);
        UINT32 arraySize_src = bytes/sizeof(T);
        if ((true == ret) && (arraySize_src > 0) && (a.size() >= arraySize_src)) {
            for (UINT32 i = 0; i < arraySize_src; i++) {
                ret = deserialize_traveller<T>::deserialize(d, a.at(i));
                if (false == ret) {
                    GOS_LOG_ERR("deserialize type: std::array, deserail data fail\n");
                    return false;
                }
            }
            return true;
        }
        GOS_LOG_ERR("deserialize type: std::array, fail by deserial dest array size is not enough\n");
        return false;
    }
};

// Begin Only For ETS Test---------------------------------------------------------------------------------------------
// ARRAYW
template <typename T, std::size_t N, UINT32 L>
struct deserialize_traveller<ARRAYW<T, N, L>> {
    inline static BOOLEAN deserialize(IDeserializer* d, ARRAYW<T, N, L>& a) {
        GOS_LOG_INFO("deserialize_traveller deserialize:%d\n", __LINE__);
        BOOLEAN ret = false;
        UINT32 bytes = a.arr.size()*sizeof(T);
        UINT32 lf_len = GetDeserializerLengthFieldLength(L);
        // GOS_LOG_INFO("deserialize type: ARRAYW, get array data by basic type.\n");
        ret = deserialize_lf(d, lf_len, bytes);
        UINT32 arraySize_src = bytes/sizeof(T);
        if ((true == ret) && (arraySize_src > 0) && (a.arr.size() >= arraySize_src)) {
            for (UINT32 i = 0; i < arraySize_src; i++) {
                ret = deserialize_traveller<T>::deserialize(d, a.arr.at(i));
                if (false == ret) {
                    GOS_LOG_ERR("deserialize type: ARRAYW, deserail data fail\n");
                    return false;
                }
            }
            return true;
        }
        GOS_LOG_ERR("deserialize type: ARRAYW, fail by deserial dest array size is not enough\n");
        return ret;
    }
};

// VECTORW
template<typename T, UINT32 L>
typename std::enable_if<std::is_trivially_copyable<T>::value, BOOLEAN>::type
VECTORWDeserializeHelper(IDeserializer* d, VECTORW<T, L>& v, UINT32 bytes) {
    GOS_LOG_INFO("deserialize_traveller deserialize:%d\n", __LINE__);
    BOOLEAN ret = false;
    if (bytes/sizeof(T) >= 0) {
        v.vec.resize(bytes/sizeof(T));
        for (auto& value : v.vec) {
            ret = deserialize_traveller<T>::deserialize(d, value);
            if (false == ret) {
                GOS_LOG_ERR("deserialize type: std::vector, deserail data fail\n");
                return false;
            }
        }
        return true;
    }
    GOS_LOG_ERR("deserialize type: VECTORW, fail by deserial dest vector size is not enough\n");
    return ret;
}

template<typename T, UINT32 L>
typename std::enable_if<!std::is_trivially_copyable<T>::value, BOOLEAN>::type
VECTORWDeserializeHelper(IDeserializer* d, VECTORW<T, L>& v, UINT32 bytes) {
    GOS_LOG_INFO("deserialize_traveller deserialize:%d\n", __LINE__);
    BOOLEAN ret = false;
    UINT32 remainingSize = bytes;
    UINT32 sizeTmp = bytes;

    while (sizeTmp > 0) {
        T t;
        ret = deserialize_traveller<T>::deserialize(d, t);
        UINT32 size = GetLength(t);
        GOS_LOG_INFO("sizeTmp:%d, remainingSize:%d, size:%d\n", sizeTmp, remainingSize, size);
        if (remainingSize >= size) {
            if (ret) {
                sizeTmp -= size;
                remainingSize -= size;
                v.vec.push_back(t);
            } else {
                break;
            }
        } else {
            GOS_LOG_ERR("deserialize type: dynamic VECTORW, fail by deserial dest vector size is not enough\n");
            return false;
        }
    }
    return ret;
}
template <typename T, UINT32 L>
struct deserialize_traveller<VECTORW<T, L>> {
    inline static BOOLEAN deserialize(IDeserializer* d, VECTORW<T, L>& v) {
        GOS_LOG_INFO("deserialize_traveller deserialize:%d\n", __LINE__);
        BOOLEAN ret = false;
        UINT32 bytes = 0;
        UINT32 lf_len = GetDeserializerLengthFieldLength(L);
        ret = deserialize_lf(d, lf_len, bytes);
        if (false == ret) {
            return false;
        }
        GOS_LOG_INFO("deserialize type: VECTORW, get vector bytes: %d.\n", bytes);
        return VECTORWDeserializeHelper(d, v, bytes);
    }
};
// End   Only For ETS Test---------------------------------------------------------------------------------------------

// std::vector
template<typename T>
typename std::enable_if<std::is_trivially_copyable<T>::value, BOOLEAN>::type
VectorDeserializeHelper(IDeserializer* d, std::vector<T>& v, UINT32 bytes) {
    GOS_LOG_INFO("deserialize_traveller deserialize:%d\n", __LINE__);
    BOOLEAN ret = false;
    if (bytes/sizeof(T) > 0) {
        v.resize(bytes/sizeof(T));
        for (auto& value : v) {
            ret = deserialize_traveller<T>::deserialize(d, value);
            if (false == ret) {
                GOS_LOG_ERR("deserialize type: std::vector, deserail data fail\n");
                return false;
            }
        }
        return true;
    }
    GOS_LOG_ERR("deserialize type: std::vector, fail by deserial dest vector size is not enough\n");
    return ret;
}

template<typename T>
typename std::enable_if<!std::is_trivially_copyable<T>::value, BOOLEAN>::type
VectorDeserializeHelper(IDeserializer* d, std::vector<T>& v, UINT32 bytes) {
    GOS_LOG_INFO("deserialize_traveller deserialize:%d\n", __LINE__);
    BOOLEAN ret = false;
    UINT32 remainingSize = bytes;
    UINT32 sizeTmp = bytes;

    while (sizeTmp > 0) {
        T t;
        ret = deserialize_traveller<T>::deserialize(d, t);
        UINT32 size = GetLength(t);
        GOS_LOG_INFO("sizeTmp:%d, remainingSize:%d, size:%d\n", sizeTmp, remainingSize, size);
        if (remainingSize >= size) {
            if (ret) {
                sizeTmp -= size;
                remainingSize -= size;
                v.push_back(t);
            } else {
                break;
            }
        } else {
            GOS_LOG_ERR("deserialize type: dynamic std::vector, fail by deserial dest vector size is not enough\n");
            return false;
        }
    }
    return ret;
}

template <typename T>
struct deserialize_traveller<std::vector<T>> {
    inline static BOOLEAN deserialize(IDeserializer* d, std::vector<T>& v) {
        GOS_LOG_INFO("deserialize_traveller deserialize:%d\n", __LINE__);
        BOOLEAN ret = false;
        UINT32 bytes = 0;
        ret = deserialize_lf(d, transProps.sizeOfArrayLengthField, bytes);
        if (false == ret) {
            return false;
        }
        if (0 == bytes) {
            return true;
        }
        GOS_LOG_INFO("deserialize type : std::vector, get vector bytes: %d.\n", bytes);
        return VectorDeserializeHelper(d, v, bytes);
    }
};

// std::vector<pair<key, value>>
template <typename TKEY, typename TVALUE>
struct deserialize_traveller<std::vector<std::pair<TKEY, TVALUE>>> {
    inline static BOOLEAN deserialize(IDeserializer* d, std::vector<std::pair<TKEY, TVALUE>>& v) {
        GOS_LOG_INFO("deserialize_traveller deserialize:%d\n", __LINE__);
        BOOLEAN ret = false;
        UINT32 bytes = 0;
        // GOS_LOG_INFO("deserialize type: std::vector<pair<,>>, get vector data by basic type.\n");
        ret = deserialize_lf(d, transProps.sizeOfArrayLengthField, bytes);
        if ((true == ret) && (bytes/sizeof(std::pair<TKEY, TVALUE>) > 0)) {
            v.resize(bytes/sizeof(std::pair<TKEY, TVALUE>));
            for (auto& value : v) {
                BOOLEAN retKey = deserialize_traveller<TKEY>::deserialize(d, value.first);
                BOOLEAN retValue = deserialize_traveller<TVALUE>::deserialize(d, value.second);
                if (false == retKey || false == retValue) {
                    GOS_LOG_ERR("deserialize type: vector<pair>, deserail data fail\n");
                    return false;
                }
            }
            return true;
        }
        GOS_LOG_INFO("deserialize type: std::vector<pair>, failed dest size is not enough\n");
        return ret;
    }
};

// std::map
// map size, map key, map key value
template <typename TKEY, typename TVALUE>
struct deserialize_traveller<std::map<TKEY, TVALUE>> {
    inline static BOOLEAN deserialize(IDeserializer* d, std::map<TKEY, TVALUE>& m) {
        GOS_LOG_INFO("deserialize_traveller deserialize:%d\n", __LINE__);
        BOOLEAN ret = false;
        INT32 mapSize_src = 0;
        // GOS_LOG_INFO("deserialize type: std::map, get vector data by basic type.\n");
        ret = deserialize_traveller<INT32>::deserialize(d, mapSize_src);
        m.clear();
        if ((true == ret) && (mapSize_src > 0)) {
            for (INT32 i = 0; i < mapSize_src; i++) {
                TKEY mapKey;
                TVALUE mapValue;
                BOOLEAN retKey = deserialize_traveller<TKEY>::deserialize(d, mapKey);
                BOOLEAN retValue = deserialize_traveller<TVALUE>::deserialize(d, mapValue);
                if (false == retKey || false == retValue) {
                    GOS_LOG_INFO("deserialize type: std::map, deserail data fail\n");
                    return false;
                }
                m.insert({mapKey, mapValue});
                // m.insert(make_pair(mapKey,mapValue));
            }
            return true;
        }
        GOS_LOG_INFO("deserialize type: std::map,failed,dest size is not enough\n");
        return ret;
    }
};

// std::unordered_map
// map size, map key, map key value
template <typename TKEY, typename TVALUE>
struct deserialize_traveller<std::unordered_map<TKEY, TVALUE>> {
    inline static BOOLEAN deserialize(IDeserializer* d, std::unordered_map<TKEY, TVALUE>& m) {
        GOS_LOG_INFO("deserialize_traveller deserialize:%d\n", __LINE__);
        BOOLEAN ret = false;
        INT32 mapSize_src = 0;
        // GOS_LOG_INFO("deserialize type: std::unordered_map, get vector data by basic type.\n");
        ret = deserialize_traveller<INT32>::deserialize(d, mapSize_src);
        m.clear();
        if ((true == ret) && (mapSize_src > 0)) {
            for (INT32 i = 0; i < mapSize_src; i++) {
                TKEY mapKey;
                TVALUE mapValue;
                BOOLEAN retKey = deserialize_traveller<TKEY>::deserialize(d, mapKey);
                BOOLEAN retValue = deserialize_traveller<TVALUE>::deserialize(d, mapValue);
                if (false == retKey || false == retValue) {
                    GOS_LOG_INFO("deserialize type: std::unordered_map, deserail data fail\n");
                    return false;
                }
                m.insert({mapKey, mapValue});
            }
            return true;
        }
        GOS_LOG_INFO("deserialize type: std::unordered_map, fail dest size is not enough\n");
        return ret;
    }
};

/**
 * @relates IDeserializer
 * @brief deserialize values from a deserializer.
 *
 * This is a parameterized function for deserialize multiple values in once call,
 * and it provides a universal method to support INT*,UINT*,FLOAT*,BOOLEAN, objects
 * which has implemented a `BOOLEAN deserialize(IDeserializer*)` signatured method,
 * and containers(vector,array,map,etc) with type check in compile time.
 *
 * @param[in] d a deserializer, which will only accessed during this call.
 * @param[out] args parameterized arguments to get deserialized values,
 * any caller pass a pointer to this function should hold the onwnership
 * of that pointer, this function only access it during the function call.
 * @return true if deserialization is succeed else false.
 */
template <typename... Args>
BOOLEAN deserialize(IDeserializer* d, Args&... args) {
    GOS_LOG_INFO("begin deserialize\n");
    return deserialize_traveller<Args...>::deserialize(d, args...);
}

// length field serialization -----------------------------------------------------------------------------------------
inline BOOLEAN deserialize_lf(IDeserializer *d, UINT32 sizeOfLengthField, UINT32& length) {
    GOS_LOG_INFO("deserialize_traveller deserialize:%d\n", __LINE__);
    BOOLEAN ret = true;
    UINT8 len_1 = 0;
    UINT16 len_2 = 0;
    UINT32 len_4 = 0;

    switch (sizeOfLengthField) {
        case 1:
            ret = deserialize(d, len_1);
            length = len_1;
            break;
        case 2:
            ret = deserialize(d, len_2);
            length = len_2;
            break;
        case 4:
            ret = deserialize(d, len_4);
            length = len_4;
            break;
        case 0:
        default:
            break;
    }
    return ret;
}
// c array serialization ----------------------------------------------------------------------------------------------
template <typename T>
BOOLEAN deserialize_carray(IDeserializer *d, T* a, size_t size) {
    GOS_LOG_INFO("deserialize_traveller deserialize:%d\n", __LINE__);
    for (size_t i = 0; i < size; i++) {
        if (!deserialize(d, a[i])) {  // bug012 反序列化失败返回false
            return false;
        }
    }
    return true;
}

// }  // namespace someip
}  // namespace com
}  // namespace dra

#endif  // _DRA_COM_SOMEIP_DESERIALIZER_H_
